package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.CacheConstant;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.JsonUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningRecordFormDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningRecordVo;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.listener.LearningRecordSyncToMysqlListener;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 学习记录表 服务实现类
 * </p>
 *
 * @author xjs
 */
@Slf4j
@Service
@ConditionalOnProperty(name = "tj.delay.type", havingValue = "springtask", matchIfMissing = false)
public class LearningRecordServiceImpl2 extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {

    @Autowired
    private ILearningLessonService lessonService;

    @Autowired
    private CourseClient courseClient;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RabbitMqHelper mqHelper;

    @Autowired
    @Lazy
    private LearningRecordSyncToMysqlListener syncToMysqlListener;

    @Override
    public String getLearningRecordKey(Long lessonId, Long sectionId, Long userId){
        return CacheConstant.LEARNING_RECORD_PREFIX+lessonId+":"+sectionId +":" + userId;
    }

    private LearningRecord getLearningRecord(Long lessonId, Long sectionId, Long userId){
        // 先查缓存
        String key =getLearningRecordKey(lessonId, sectionId, userId);
        String json = redisTemplate.opsForValue().get(key);
        // 如果缓存有，直接返回
        if(StringUtils.isNotBlank(json)){
            return JsonUtils.toBean(json, LearningRecord.class);
        }
        // 如果没有，再查数据库
        LearningRecord oldRecord = this.lambdaQuery().eq(LearningRecord::getLessonId, lessonId)
                .eq(LearningRecord::getSectionId, sectionId)
                .eq(LearningRecord::getUserId, userId)
                .one();
        // 如果数据库有，放入缓存
        if(oldRecord != null){
            redisTemplate.opsForValue().set(key, JsonUtils.toJsonStr(oldRecord));
        }
        return oldRecord;
    }

    @Override
    public void submitLearningRecord(LearningRecordFormDTO dto) {
        Long userId = UserContext.getUser();
        SectionType sectionType = dto.getSectionType();
        // 查询lesson
        LearningLesson lesson = lessonService.getById(dto.getLessonId());
        if(lesson == null){
            log.error("根据lessonid：{}查询不到lesson信息", dto.getLessonId());
            throw new BizIllegalException("网络异常");
        }
        // 考试
        if(sectionType ==SectionType.EXAM ){
            // 新增学习记录，insert
            addLearningRecord(lesson, dto, true);
            // 判断是否全部学完，
            Integer oldNum = lesson.getLearnedSections();
            // feign，查询课程的总的小节数量
            CourseFullInfoDTO course = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
            if(course == null){
                log.error("根据courseid：{}查询不到course信息", lesson.getCourseId());
                throw new BizIllegalException("网络异常");
            }
            Integer totalSectionNum = course.getSectionNum();
            // 如果学完所有章节，更新课表的状态为已经学完
            if(oldNum + 1 >= totalSectionNum){
                lesson.setStatus(LessonStatus.FINISHED.getValue());
            }else{
                lesson.setStatus(LessonStatus.LEARNING.getValue());
            }
            // 更新课表：已经学习的小节数量，最近学习的小节，最近学习的时间
            lesson.setLearnedSections(oldNum + 1);
            lesson.setLatestSectionId(dto.getSectionId());
            lesson.setLatestLearnTime(LocalDateTime.now());
            lesson.setUpdateTime(LocalDateTime.now());
            lessonService.updateById(lesson);
        }else{
            // 视频
            // 判断学习记录是否存在，根据lessonId、sectionId、userId
            LearningRecord oldRecord = getLearningRecord(dto.getLessonId(), dto.getSectionId(), userId);
            // 如果不存在，
            if(oldRecord == null){
                log.info("视频-record不存在，lessonId：{}， sectionId：{}", dto.getLessonId(), dto.getSectionId());
                // 新增学习记录
                addLearningRecord(lesson, dto, false);
                // 更新课表：最近学习的小节和最近学习的时间
                lesson.setLatestSectionId(dto.getSectionId());
                lesson.setLatestLearnTime(LocalDateTime.now());
                lesson.setStatus(LessonStatus.LEARNING.getValue());
                lesson.setUpdateTime(LocalDateTime.now());
                lessonService.updateById(lesson);
            }else{
                log.info("视频-record已经存在，lessonId：{}， sectionId：{}", dto.getLessonId(), dto.getSectionId());
                // 如果存在
                // 1. 更新学习记录：Moment、FinishTime、Finished
                oldRecord.setMoment(dto.getMoment());
                oldRecord.setUpdateTime(LocalDateTime.now());
                // 判断是否是第一次学完当前章节：（1）finish=false（2）进度超过50%
                boolean oldFinish = oldRecord.getFinished();
                boolean over = dto.getMoment()  * 2 >=  dto.getDuration();
                boolean isFirstFinish = !oldFinish && over;
                if(isFirstFinish){
                    oldRecord.setFinishTime(LocalDateTime.now());
                    oldRecord.setFinished(true);
                    oldRecord.setFirstFinish(true);
                }else{
                    oldRecord.setFirstFinish(false);
                }
                // 更新redis
                String key = getLearningRecordKey(dto.getLessonId(), dto.getSectionId(), userId);
                redisTemplate.opsForValue().set(key, JsonUtils.toJsonStr(oldRecord));
                log.info("视频-更新redis，进度：{}", oldRecord.getMoment());
                // 记录缓存的key到redis的set
                redisTemplate.opsForSet().add(CacheConstant.LEARNING_RECORD_KEYS, key);
//                mqHelper.sendDelayMessage(MqConstants.Exchange.LEARNING_DELAY_EXCHANGE,
//                        MqConstants.Key.LEARNING_RECORD_KEY, oldRecord, Duration.ofSeconds(20) );
                log.info("视频-发送延迟消息，进度：{}", oldRecord.getMoment());
                // this.updateById(record); 不更新数据库，暂存到redis
                // 2. 更新课表：LatestLearnTime、LatestSectionId、LearnedSections、Status
                //  是第一次学完，课表：已学习小节数量+1，判断是否学完整个课，修改状态
                //  不管是否学完，课表：最近学习的小节和最近学习的时间
//                if(isFirstFinish){
//                    Integer oldNum = lesson.getLearnedSections();
//                    lesson.setLearnedSections(oldNum+1);
//                    // feign，查询课程的总的小节数量
//                    CourseFullInfoDTO course = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
//                    if(course == null){
//                        log.error("根据courseid：{}查询不到course信息", lesson.getCourseId());
//                        throw new BizIllegalException("网络异常");
//                    }
//                    Integer totalSectionNum = course.getSectionNum();
//                    // 如果学完所有的章节，更新课表的状态为已经学完
//                    if(oldNum + 1 >= totalSectionNum){
//                        lesson.setStatus(LessonStatus.FINISHED.getValue());
//                    }
//                }
//                lesson.setUpdateTime(LocalDateTime.now());
//                lesson.setLatestLearnTime(LocalDateTime.now());
//                lesson.setLatestSectionId(dto.getSectionId());
                // lessonService.updateById(lesson); 不更新数据库，暂存到redis
            }
        }
    }

    private void addLearningRecord(LearningLesson lesson, LearningRecordFormDTO dto, boolean finish){
        // 新增学习记录，insert
        LearningRecord learningRecord = BeanUtil.copyProperties(dto, LearningRecord.class);
        learningRecord.setCourseId(lesson.getCourseId());
        if(finish){
            learningRecord.setFinished(true);
            learningRecord.setFinishTime(LocalDateTime.now());
        }
        learningRecord.setCreateTime(LocalDateTime.now());
        learningRecord.setUpdateTime(LocalDateTime.now());
        learningRecord.setUserId(UserContext.getUser());
        learningRecord.setSectionType(dto.getSectionType().getValue());
        this.save(learningRecord);
    }

    @Override
    public LearningRecordVo getLearnRecord(Long courseId) {
        Long userId = UserContext.getUser();
        LearningRecordVo vo = new LearningRecordVo();
        // 根据userId和courseId查询learing_record列表
        List<LearningRecord> recordList = this.lambdaQuery()
                .eq(LearningRecord::getUserId, userId)
                .eq(LearningRecord::getCourseId, courseId)
                .orderByDesc(LearningRecord::getUpdateTime)
                .list();
        if(CollUtil.isEmpty(recordList)){
            // 根据userId和courseId查询lession
            LearningLesson lesson = lessonService.getByUserIdCourseId(userId, courseId);
            vo.setId(lesson.getId());
            return vo;
        }
        // 找出update_time最大的作为latest_section_id
        LearningRecord latestSectionRecord = recordList.get(0);
        // 填充
        vo.setId(latestSectionRecord.getLessonId());
        vo.setLatestSectionId(latestSectionRecord.getSectionId());
        vo.setRecords(recordList.stream().map(r -> {
            LearningRecordVo.RecordVo recordVo = new LearningRecordVo.RecordVo();
            recordVo.setSectionId(r.getSectionId());
            recordVo.setMoment(r.getMoment());
            recordVo.setFinished(r.getFinished());
            return recordVo;
        }).collect(Collectors.toList()));
        return vo;
    }
}
